﻿
// FilmServerDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "FilmServer.h"
#include "FilmServerDlg.h"
#include "afxdialogex.h"
#include "Utilities.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define UM_ADD_LOG WM_USER+1
#define UM_SERVER_STOP WM_USER+2


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CFilmServerDlg 对话框



CFilmServerDlg::CFilmServerDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_FILMSERVER_DIALOG, pParent)
	, m_Port(_T(""))
	, m_selPrinter(_T(""))
	, m_loglevel(0)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_brBlack.CreateSolidBrush(RGB(0, 0, 0));
}

void CFilmServerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT_LOG, m_log);
	DDX_Control(pDX, IDC_COMBO_PRINTER, m_cmbPrinter);
	DDX_Text(pDX, IDC_EDIT_PORT, m_Port);
	DDX_CBString(pDX, IDC_COMBO_PRINTER, m_selPrinter);
	DDX_Control(pDX, IDC_COMBO_LL, m_cmbLL);
	DDX_CBIndex(pDX, IDC_COMBO_LL, m_loglevel);
}

BEGIN_MESSAGE_MAP(CFilmServerDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_START, &CFilmServerDlg::OnBnClickedButtonStart)
	ON_CBN_SELCHANGE(IDC_COMBO_PRINTER, &CFilmServerDlg::OnSelchangeComboPrinter)
	ON_MESSAGE(UM_ADD_LOG, &CFilmServerDlg::OnAddLog)
	ON_MESSAGE(UM_SERVER_STOP, &CFilmServerDlg::OnServerStop)
	ON_WM_CTLCOLOR()
	ON_BN_CLICKED(IDC_BUTTON_CLEAR, &CFilmServerDlg::OnBnClickedButtonClear)
	ON_WM_DESTROY()
	ON_CBN_SELCHANGE(IDC_COMBO_LL, &CFilmServerDlg::OnSelchangeComboLl)
END_MESSAGE_MAP()


// CFilmServerDlg 消息处理程序

BOOL CFilmServerDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	ReadPrinterCfg("dcmpstat.cfg");

	for (int i=0; i<m_printers.size(); i++)
	{
		std::string printerName = m_printers.at(i).PrinterName;
		m_cmbPrinter.AddString(printerName.c_str());
	}

	if (m_printers.size() > 0) {
		m_cmbPrinter.SetCurSel(0);
		OnSelchangeComboPrinter();
	}

	m_cmbLL.AddString(_T("调试"));  // +d
	m_cmbLL.AddString(_T("通知"));  // -d
	//m_cmbLL.AddString(_T("警告"));  // -v
	m_cmbLL.AddString(_T("错误"));  
	m_cmbLL.SetCurSel(0);

	m_log.SetLimitText(0);

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void CFilmServerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CFilmServerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CFilmServerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CFilmServerDlg::OnBnClickedButtonStart()
{
	if (m_bStop) {
		if (Start()) {
			GetDlgItem(IDC_BUTTON_START)->SetWindowText(_T("停止"));
		}
	}
	else {
		if (Stop()) {
			GetDlgItem(IDC_BUTTON_START)->SetWindowText(_T("启动"));
		}
	}
}

int CFilmServerDlg::ReadPrinterCfg(const char* cfg)
{
	PrinterCfg printerCfg(cfg);
	return printerCfg.GetPrinters(m_printers);
}

void CFilmServerDlg::addLog(LPCTSTR format, ...)
{
	va_list args;
	va_start(args, format);

	CString strResult;
	strResult.FormatV(format, args); 

	va_end(args);

	if (strResult.Right(2) != _T("\r\n"))
		strResult += _T("\r\n");

	::SendMessage(this->m_hWnd, UM_ADD_LOG, (WPARAM)(LPCTSTR)strResult, 0);

}

int CFilmServerDlg::Start()
{
	UpdateData();
	if (m_selPrinter.IsEmpty()) {
		addLog(_T("[%s] 请选择打印机!"), GetLogTimeStr().c_str());
		return FALSE;
	}

	m_bStop = FALSE;

	SECURITY_ATTRIBUTES sa;
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;

	CreatePipe(&m_hReadPipe, &m_hWritePipe, &sa, 0);

	m_thPipe = std::thread([=]() {
		std::string strResult;
		DWORD bytesRead = 0;
		DWORD totalAvail = 0;
		int ret = 0;
		const DWORD BUF_SIZE = 1024;
		char cbBuf[BUF_SIZE+1] = { 0 };
		do
		{
			DWORD totalRead = 0;
			BOOL success = PeekNamedPipe(m_hReadPipe, NULL, 0, NULL, &totalAvail, NULL);
			if (!success) {
				ret = GetLastError();
				break;
			}

			if (totalAvail <= 0) {
				continue;
			}

			ZeroMemory(cbBuf, BUF_SIZE+1);
			success = ReadFile(m_hReadPipe, cbBuf, BUF_SIZE, &bytesRead, NULL);

			if (bytesRead == 0)
			{
				ret = -1;
				break;
			}

			strResult = cbBuf;
			totalRead += bytesRead;

			while (totalRead < totalAvail)
			{
				ZeroMemory(cbBuf, BUF_SIZE+1);
				success = ReadFile(m_hReadPipe, cbBuf, BUF_SIZE, &bytesRead, NULL);

				if (!success || bytesRead == 0) {
					break;
				}

				strResult += cbBuf;
				totalRead += bytesRead;
			}

			addLog(strResult.c_str());
			
			if (strResult.find("F: ") != std::string::npos 
				|| strResult.find("E: ") != std::string::npos
				|| strResult.find("error: ") != std::string::npos)
			{
				ret = -2;
				break;
			}

			
		} while (!m_bStop);

		PostMessage(UM_SERVER_STOP, ret, 0);

	});

	m_thPipe.detach();

	CString commandLine;
	CString exeName;

	STARTUPINFO si = { 0 };
	si.cb = sizeof(STARTUPINFO);
	GetStartupInfo(&si);
	si.wShowWindow = SW_HIDE;
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	si.hStdError = m_hWritePipe;
	si.hStdOutput = m_hWritePipe;
	

	std::string appDir = GetAppPath();
	std::string dataDir = appDir + "database\\";
	std::string logDir = appDir + "spool\\";
	MakePath(dataDir);
	MakePath(logDir);

	exeName.Format(_T("%sdcmprscp.exe"), GetAppPath().c_str());
	commandLine.Format(_T(" -c dcmpstat.cfg -p %s"), m_selPrinter);

	if (m_loglevel == 1) {
		commandLine += " -v";
	}

	if (m_loglevel == 0) {
		commandLine += " -d";
	}

	addLog(_T("[%s] 进程命令[dcmprscp.exe %s]"),  GetLogTimeStr().c_str(), commandLine);

	SetCurrentDirectory(appDir.c_str());
	if (!CreateProcess((LPCTSTR)exeName, 
			(LPSTR)(LPCTSTR)commandLine, 
			NULL, 
			NULL, 
			TRUE, 
			CREATE_NEW_CONSOLE,
			NULL, 
			NULL, 
			&si, 
			&m_pi))//创建子进程
	{
		CloseHandle(m_pi.hProcess);
		CloseHandle(m_pi.hThread);
		CloseHandle(m_hReadPipe);
		CloseHandle(m_hWritePipe);
		addLog(_T("[%s] 创建进程失败, 错误代码: %d"), GetLogTimeStr().c_str(), GetLastError());
		return FALSE;
	}

	GetDlgItem(IDC_COMBO_PRINTER)->EnableWindow(FALSE);

	return TRUE;
	
}

int CFilmServerDlg::Stop()
{
	m_bStop = TRUE;
	TerminateProcess(m_pi.hProcess, 0);

	//if (m_thPipe.joinable()) {
	//	m_thPipe.join();
	//}

	//WaitForSingleObject(m_pi.hProcess, INFINITE);

	return TRUE;
}

void CFilmServerDlg::OnSelchangeComboPrinter()
{
	int idx = m_cmbPrinter.GetCurSel();
	if (idx == -1) return;

	m_selPrinter = m_printers.at(idx).PrinterName.c_str();
	m_Port = m_printers.at(idx).Port.c_str();
	UpdateData(FALSE);

}


LRESULT CFilmServerDlg::OnAddLog(WPARAM wParam, LPARAM lParam)
{
	CString logStr = (LPCTSTR)wParam;

	if (m_log.m_hWnd && IsWindow(m_log.m_hWnd))
	{
		UINT nLmt = m_log.GetLimitText();
		int nTextLength = m_log.GetWindowTextLength();
		if ((UINT)(nTextLength + logStr.GetLength()) >= nLmt)
		{
			int nPos = m_log.LineIndex(100);
			m_log.SetSel(0, nPos);
			m_log.ReplaceSel(_T(""), FALSE);
		}

		m_log.SetSel(nTextLength, nTextLength);
		m_log.ReplaceSel(logStr);
		m_log.PostMessage(EM_SETSEL, -1, -1);
	}

	return 0;
}

LRESULT CFilmServerDlg::OnServerStop(WPARAM wParam, LPARAM lParam)
{
	m_bStop = TRUE;
	addLog(_T("[%s] 打印服务结束, 代码: %d"), GetLogTimeStr().c_str(), wParam);
	GetDlgItem(IDC_BUTTON_START)->SetWindowText(_T("启动"));
	GetDlgItem(IDC_COMBO_PRINTER)->EnableWindow(TRUE);

	CloseHandle(m_pi.hProcess);
	CloseHandle(m_pi.hThread);
	CloseHandle(m_hReadPipe);
	CloseHandle(m_hWritePipe);

	return 0;
}

HBRUSH CFilmServerDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

	// TODO:  在此更改 DC 的任何特性
	if (pWnd && pWnd->m_hWnd == m_log.GetSafeHwnd())
	{
		pDC->SetBkColor(0);
		pDC->SetTextColor(RGB(220, 220, 220));
		return m_brBlack;
	}

	// TODO:  如果默认的不是所需画笔，则返回另一个画笔
	return hbr;
}


void CFilmServerDlg::OnBnClickedButtonClear()
{
	m_log.SetSel(0, -1);
	m_log.ReplaceSel(_T(""), FALSE);
}


void CFilmServerDlg::OnDestroy()
{
	CDialogEx::OnDestroy();

	// TODO: 在此处添加消息处理程序代码
	if (!m_bStop) {
		Stop();
	}
}


void CFilmServerDlg::OnSelchangeComboLl()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData();
}
